package com.alit.ibot.robot.wechat.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;

import org.apache.commons.io.IOUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.alit.ibot.robot.projectvariable.PVK;
import com.alit.ibot.robot.projectvariable.PVU;
import com.alit.ibot.robot.wechat.data.MediaId;
import com.alit.ibot.robot.wechat.data.WechatMessageType;
import com.litong.utils.digest.SHA1Util;

import lombok.extern.slf4j.Slf4j;

/**
 * @author litong
 * @date 2019年6月1日_上午12:35:59
 * @version 1.0
 * @desc
 */
@Slf4j
public class WechatUploadUtil {

  /**
   * 与微信无关，只是下载文件到本地的
   */
  public static String downloadRemoteFile(String localFilePath, String remoteURL) {
    log.info("开始下载:" + System.currentTimeMillis());
    System.setProperty("file.encoding", "utf-8"); // 设置系统文件编码
    URL httpURL = null;
    try {
      httpURL = new URL(remoteURL);// 封装成URL
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    HttpURLConnection httpConnection = null;
    try {
      httpConnection = (HttpURLConnection) httpURL.openConnection(); // 打开http连接
    } catch (IOException e) {
      e.printStackTrace();
    }
    httpConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8"); // 设置请求头,不知道为什么这么设置
    httpConnection.setDoInput(true);
    httpConnection.setDoOutput(true);

    InputStream inputStream = null;
    BufferedInputStream bufferedInputStream = null;
    FileOutputStream fileOutputStream = null;
    BufferedOutputStream bufferedOutputStream = null;
    int length = 0;
    byte[] buffer = new byte[1024 * 1024 * 2]; // 一次读取2M
    try {
      inputStream = httpConnection.getInputStream(); // 获取远程文件流
      bufferedInputStream = new BufferedInputStream(inputStream); // 使用缓冲流

      fileOutputStream = new FileOutputStream(localFilePath);
      bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
      while ((length = bufferedInputStream.read(buffer)) != -1) {
        bufferedOutputStream.write(buffer, 0, length); // 将文件保存到outputStream
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      IOUtils.closeQuietly(bufferedOutputStream);
      IOUtils.closeQuietly(bufferedInputStream);
    }
    log.info("结束下载:" + System.currentTimeMillis());
    return localFilePath;
  }

  /**
   * 模拟form表单的形式 ，上传文件 以输出流的形式把文件写入到url中，然后用输入流来获取url的响应
   */
  public static String send(String accessToken, String localFilePath, String localFileType) throws IOException {
    log.info("开始上传到微信平台:" + System.currentTimeMillis());
    String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type="
        + localFileType; // 拼接成上传文件的URL
    // log.info("开始上传图片:" + url + "," + localFilePath);
    File file = new File(localFilePath);
    if (!file.exists() || !file.isFile()) { // 如果文件不存在抛出异常
      throw new IOException("文件不存在");
    }
    URL httpURL = new URL(url); // 转为URL类
    HttpURLConnection httpURLConnection = (HttpURLConnection) httpURL.openConnection(); // 打开连接

    httpURLConnection.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
    httpURLConnection.setDoInput(true);
    httpURLConnection.setDoOutput(true);
    httpURLConnection.setUseCaches(false); // post方式不能使用缓存
    // 设置请求头信息
    httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
    httpURLConnection.setRequestProperty("Charset", "UTF-8");

    // 设置边界
    String BOUNDARY = "----------" + System.currentTimeMillis();
    httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

    // 请求正文信息
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append("--"); // 必须多两道线
    stringBuffer.append(BOUNDARY);
    stringBuffer.append("\r\n");
    stringBuffer.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
    stringBuffer.append("Content-Type:application/octet-stream\r\n\r\n");

    byte[] head = stringBuffer.toString().getBytes("utf-8");

    // 获得输出流,将远程url输出的部分
    OutputStream dataOutputStream = new DataOutputStream(httpURLConnection.getOutputStream());
    // 输出表头
    dataOutputStream.write(head);

    // 文件正文部分
    // 把文件一流文件方式 推入到url中
    DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
    int length = 0;
    byte[] bufferOut = new byte[1024 * 1024 * 2]; // 2M
    while ((length = dataInputStream.read(bufferOut)) != -1) {
      dataOutputStream.write(bufferOut, 0, length);
    }
    dataInputStream.close();

    // 结尾部分
    byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
    dataOutputStream.write(foot);
    dataOutputStream.flush();
    dataOutputStream.close();

    stringBuffer = new StringBuffer();
    BufferedReader bufferedReader = null;
    try {
      // 定义BufferedReader输入流来读取URL的响应
      bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
      String line = null;
      while ((line = bufferedReader.readLine()) != null) {
        stringBuffer.append(line);
      }
      log.info("结束上传到微信平台:" + System.currentTimeMillis());
      log.info("文件上传完成,返回信息" + stringBuffer);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      IOUtils.closeQuietly(bufferedReader);
    }
    JSONObject jsonObj = JSONObject.parseObject(stringBuffer.toString());
    String mediaId = null;
    try {
      if (localFileType.equals(WechatMessageType.image)) {
        mediaId = jsonObj.getString("media_id");
      } else if (localFileType.equals(WechatMessageType.thumb)) {
        mediaId = jsonObj.getString("thumb_media_id");
      } else {
        mediaId = jsonObj.getString("media_id");
      }
    } catch (Exception e) {
      log.error("发送错误:" + jsonObj.toString());
      e.printStackTrace();
    }
    return mediaId;
  }

  /**
   * 上传远程文件到微信平台
   * 
   * @param url
   * @param type
   * @return
   */
  public static String fromURLtoWechat(String url, String type) {
    String dir = PVU.getValue(PVK.projectDownloadDir);

    String localPath = null;
    if (type.equals(WechatMessageType.image) || type.equals(WechatMessageType.thumb)) { // 如果是图片类型,添加jpg后缀
      long time = new Date().getTime();
      localPath = dir + File.separator + time + ".jpg";
    }else if(type.equals(WechatMessageType.video)) {
      long time = new Date().getTime();
      localPath = dir + File.separator + time + ".mp4";
    }

    if (!StringUtils.isEmpty(url)) {
      WechatUploadUtil.downloadRemoteFile(localPath, url);// 下载文件保存到本地
      log.info("已将远程文件保存到本地:" + localPath);
    } else {
      log.info("远程文件为空");
      return null;
    }

    // 获取文件的sha1值,查询缓存,判断是否过期,如果不过期,返回缓存中的mediaId
    String sha1 = SHA1Util.getSha1(localPath);
    MediaId cacheMediaId = WechatMediaIdCache.get(sha1);
    if (cacheMediaId != null && System.currentTimeMillis() < cacheMediaId.getExpireTime()) {
      String mediaId = cacheMediaId.getMediaId();
      log.info("返回缓存中的MediaId:" + mediaId);
      return mediaId;
    }

    File file = new File(localPath);
    String mediaId = null;
    if (file.exists()) { // 如果本地存在,则上传
      mediaId = WechatUploadUtil.upload(localPath, type);
    }
    // 文件上传完后缓存mediaId
    long expireTime = System.currentTimeMillis() + 3 * 24 * 60 * 60 * 1000;
    WechatMediaIdCache.add(sha1, url, localPath, mediaId, expireTime);
    return mediaId;
  }

  /**
   * 上传本地文件到微信平台
   * 
   * @return
   */
  public static String upload(String localFilePath, String type) {
    String accessToken = WechatAccessTokenUtil.getAccessToken(); // 获取access_token
    String mediaId = null;
    try {
      mediaId = WechatUploadUtil.send(accessToken, localFilePath, type); // 发送文件
    } catch (IOException e) {
      e.printStackTrace();
    }
    return mediaId;
  }

}
